home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / comms / non-internet / samba / source / mangle.c < prev    next >
C/C++ Source or Header  |  1996-06-26  |  17KB  |  611 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Name mangling
  5.    Copyright (C) Andrew Tridgell 1992-1995
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include "includes.h"
  23. #include "loadparm.h"
  24.  
  25. extern int DEBUGLEVEL;
  26. extern int case_default;
  27. extern BOOL case_mangle;
  28.  
  29. /****************************************************************************
  30. provide a checksum on a string
  31. ****************************************************************************/
  32. int str_checksum(char *s)
  33. {
  34.   int res = 0;
  35.   int c;
  36.   int i=0;
  37.   while (*s)
  38.     {
  39.       c = *s;
  40.       res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
  41.       s++; i++;
  42.     }
  43.   return(res);
  44. }
  45.  
  46. /****************************************************************************
  47. return True if a name is a special msdos reserved name
  48. ****************************************************************************/
  49. static BOOL is_reserved_msdos(char *fname)
  50. {
  51.   char upperFname[13];
  52.   char *p;
  53.  
  54.   StrnCpy (upperFname, fname, 12);
  55.  
  56.   /* lpt1.txt and con.txt etc are also illegal */
  57.   p=strchr(upperFname,'.');
  58.   if (p)
  59.    *p='\0';
  60.   strupper (upperFname);
  61.   if ((strcmp(upperFname,"CLOCK$") == 0) ||
  62.     (strcmp(upperFname,"CON") == 0) ||
  63.     (strcmp(upperFname,"AUX") == 0) ||
  64.     (strcmp(upperFname,"COM1") == 0) ||
  65.     (strcmp(upperFname,"COM2") == 0) ||
  66.     (strcmp(upperFname,"COM3") == 0) ||
  67.     (strcmp(upperFname,"COM4") == 0) ||
  68.     (strcmp(upperFname,"LPT1") == 0) ||
  69.     (strcmp(upperFname,"LPT2") == 0) ||
  70.     (strcmp(upperFname,"LPT3") == 0) ||
  71.     (strcmp(upperFname,"NUL") == 0) ||
  72.     (strcmp(upperFname,"PRN") == 0))
  73.       return (True) ;
  74.  
  75.   return (False);
  76. }
  77.  
  78.  
  79.  
  80. /****************************************************************************
  81. return True if a name is in 8.3 dos format
  82. ****************************************************************************/
  83. BOOL is_8_3(char *fname)
  84. {
  85.   int len;
  86.   char *dot_pos;
  87.   char *slash_pos = strrchr(fname,'/');
  88.   int l;
  89.  
  90.   if (slash_pos) fname = slash_pos+1;
  91.   len = strlen(fname);
  92.  
  93.   dot_pos = strchr(fname,'.');
  94.  
  95.   DEBUG(5,("checking %s for 8.3\n",fname));
  96.  
  97.   if (case_mangle)
  98.     switch (case_default)
  99.       {
  100.       case CASE_LOWER:
  101.     if (strhasupper(fname)) return(False);
  102.     break;
  103.       case CASE_UPPER:
  104.     if (strhaslower(fname)) return(False);
  105.     break;
  106.       }
  107.  
  108.   /* can't be longer than 12 chars */
  109.   if (len == 0 || len > 12)
  110.     return(False);
  111.  
  112.   /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
  113.   if (is_reserved_msdos(fname))
  114.     return(False);
  115.  
  116.   /* can't contain invalid dos chars */
  117.   /* Windows use the ANSI charset.
  118.      But filenames are translated in the PC charset.
  119.      This Translation may be more or less relaxed depending
  120.      the Windows application. */
  121.  
  122.   /* %%% A nice improvment to name mangling would be to translate
  123.      filename to ANSI charset on the smb server host */
  124.  
  125.   {
  126.     char *p = fname;
  127. #ifdef KANJI
  128.     dot_pos = 0;
  129.     while (*p)
  130.       {
  131.       if (is_shift_jis (*p)) {
  132.           p += 2;
  133.       } else if (is_kana (*p)) {
  134.           p ++;
  135.       } else {
  136.           if (*p == '.' && !dot_pos)
  137.           dot_pos = (char *) p;
  138.           if (!isdoschar(*p))
  139.           return(False);
  140.           p++;
  141.       }
  142.       }      
  143. #else
  144.     while (*p)
  145.       {
  146.     if (!isdoschar(*p))
  147.       return(False);
  148.     p++;
  149.       }      
  150. #endif /* KANJI */
  151.   }
  152.  
  153.   /* no dot and less than 9 means OK */
  154.   if (!dot_pos)
  155.     return(len <= 8);
  156.     
  157.   l = PTR_DIFF(dot_pos,fname);
  158.  
  159.   /* base must be at least 1 char except special cases . and .. */
  160.   if (l == 0)
  161.     return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0);
  162.  
  163.   /* base can't be greater than 8 */
  164.   if (l > 8)
  165.     return(False);
  166.  
  167.   if (lp_strip_dot() && 
  168.       len - l == 1 &&
  169.       !strchr(dot_pos+1,'.'))
  170.     {
  171.       *dot_pos = 0;
  172.       return(True);
  173.     }
  174.  
  175.   /* extension must be between 1 and 3 */
  176.   if ( (len - l < 2 ) || (len - l > 4) )
  177.     return(False);
  178.  
  179.   /* extension can't have a dot */
  180.   if (strchr(dot_pos+1,'.'))
  181.     return(False);
  182.  
  183.   /* must be in 8.3 format */
  184.   return(True);
  185. }
  186.  
  187.  
  188.  
  189. /*
  190. keep a stack of name mangling results - just
  191. so file moves and copies have a chance of working
  192. */
  193. fstring *mangled_stack = NULL;
  194. int mangled_stack_size = 0;
  195. int mangled_stack_len = 0;
  196.  
  197. /****************************************************************************
  198. create the mangled stack
  199. ****************************************************************************/
  200. void create_mangled_stack(int size)
  201. {
  202.   if (mangled_stack)
  203.     {
  204.       free(mangled_stack);
  205.       mangled_stack_size = 0;
  206.       mangled_stack_len = 0;
  207.     }
  208.   if (size > 0)
  209.     mangled_stack = (fstring *)malloc(sizeof(fstring)*size);
  210.   if (mangled_stack) mangled_stack_size = size;
  211. }
  212.  
  213. /****************************************************************************
  214. push a mangled name onto the stack
  215. ****************************************************************************/
  216. static void push_mangled_name(char *s)
  217. {
  218.   int i;
  219.   char *p;
  220.  
  221.   if (!mangled_stack)
  222.     return;
  223.  
  224.   for (i=0;i<mangled_stack_len;i++)
  225.     if (strcmp(s,mangled_stack[i]) == 0)
  226.       {
  227.     array_promote(mangled_stack[0],sizeof(fstring),i);    
  228.     return;
  229.       }
  230.  
  231.   memmove(mangled_stack[1],mangled_stack[0],
  232.       sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1));
  233.   strcpy(mangled_stack[0],s);
  234.   p = strrchr(mangled_stack[0],'.');
  235.   if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4))
  236.     *p = 0;
  237.   mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1);
  238. }
  239.  
  240. /****************************************************************************
  241. check for a name on the mangled name stack
  242. ****************************************************************************/
  243. BOOL check_mangled_stack(char *s)
  244. {
  245.   int i;
  246.   pstring tmpname;
  247.   char extension[5];
  248.   char *p = strrchr(s,'.');
  249.   BOOL check_extension = False;
  250.  
  251.   extension[0] = 0;
  252.  
  253.   if (!mangled_stack) return(False);
  254.  
  255.   if (p)
  256.     {
  257.       check_extension = True;
  258.       StrnCpy(extension,p,4);
  259.       strlower(extension); /* XXXXXXX */
  260.     }
  261.  
  262.   for (i=0;i<mangled_stack_len;i++)
  263.     {
  264.       strcpy(tmpname,mangled_stack[i]);
  265.       mangle_name_83(tmpname);
  266.       if (strequal(tmpname,s))
  267.     {
  268.       strcpy(s,mangled_stack[i]);
  269.       break;
  270.     }
  271.       if (check_extension && !strchr(mangled_stack[i],'.'))
  272.     {
  273.       strcpy(tmpname,mangled_stack[i]);
  274.       strcat(tmpname,extension);
  275.       mangle_name_83(tmpname);
  276.       if (strequal(tmpname,s))
  277.         {
  278.           strcpy(s,mangled_stack[i]);
  279.           strcat(s,extension);
  280.           break;
  281.         }      
  282.     }
  283.     }
  284.  
  285.   if (i < mangled_stack_len)
  286.     {
  287.       DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i]));
  288.       array_promote(mangled_stack[0],sizeof(fstring),i);
  289.       return(True);      
  290.     }
  291.  
  292.   return(False);
  293. }    
  294.  
  295. static char *map_filename(char *s, /* This is null terminated */
  296.               char *pattern, /* This isn't. */
  297.               int len) /* This is the length of pattern. */
  298. {
  299.   static pstring matching_bit;  /* The bit of the string which matches */
  300.                                 /* a * in pattern if indeed there is a * */
  301.   char *sp;                     /* Pointer into s. */
  302.   char *pp;                     /* Pointer into p. */
  303.   char *match_start;            /* Where the matching bit starts. */
  304.   pstring pat;
  305.  
  306.   StrnCpy(pat, pattern, len);   /* Get pattern into a proper string! */
  307.   strcpy(matching_bit,"");      /* Match but no star gets this. */
  308.   pp = pat;                     /* Initialise the pointers. */
  309.   sp = s;
  310.   if ((len == 1) && (*pattern == '*')) {
  311.     return NULL;                /* Impossible, too ambiguous for */
  312.                                 /* words! */
  313.   }
  314.  
  315.   while ((*sp)                  /* Not the end of the string. */
  316.          && (*pp)               /* Not the end of the pattern. */
  317.          && (*sp == *pp)        /* The two match. */
  318.          && (*pp != '*')) {     /* No wildcard. */
  319.     sp++;                       /* Keep looking. */
  320.     pp++;
  321.   }
  322.   if (!*sp && !*pp)             /* End of pattern. */
  323.     return matching_bit;        /* Simple match.  Return empty string. */
  324.   if (*pp == '*') {
  325.     pp++;                       /* Always interrested in the chacter */
  326.                                 /* after the '*' */
  327.     if (!*pp) {                 /* It is at the end of the pattern. */
  328.       StrnCpy(matching_bit, s, sp-s);
  329.       return matching_bit;
  330.     } else {
  331.       /* The next character in pattern must match a character further */
  332.       /* along s than sp so look for that character. */
  333.       match_start = sp;
  334.       while ((*sp)              /* Not the end of s. */
  335.              && (*sp != *pp))   /* Not the same  */
  336.         sp++;                   /* Keep looking. */
  337.       if (!*sp) {               /* Got to the end without a match. */
  338.         return NULL;
  339.       } else {                  /* Still hope for a match. */
  340.         /* Now sp should point to a matching character. */
  341.         StrnCpy(matching_bit, match_start, sp-match_start);
  342.         /* Back to needing a stright match again. */
  343.         while ((*sp)            /* Not the end of the string. */
  344.                && (*pp)         /* Not the end of the pattern. */
  345.                && (*sp == *pp)) { /* The two match. */
  346.           sp++;                 /* Keep looking. */
  347.           pp++;
  348.         }
  349.         if (!*sp && !*pp)       /* Both at end so it matched */
  350.           return matching_bit;
  351.         else
  352.           return NULL;
  353.       }
  354.     }
  355.   }
  356.   return NULL;                  /* No match. */
  357. }
  358.  
  359.  
  360. /* this is the magic char used for mangling */
  361. char magic_char = '~';
  362.  
  363.  
  364. /****************************************************************************
  365. determine whther is name could be a mangled name
  366. ****************************************************************************/
  367. BOOL is_mangled(char *s)
  368. {
  369.   char *m = strchr(s,magic_char);
  370.   if (!m) return(False);
  371.  
  372.   /* we use two base 36 chars efore the extension */
  373.   if (m[1] == '.' || m[1] == 0 ||
  374.       m[2] == '.' || m[2] == 0 ||
  375.       (m[3] != '.' && m[3] != 0))
  376.     return(is_mangled(m+1));
  377.  
  378.   /* it could be */
  379.   return(True);
  380. }
  381.  
  382.  
  383.  
  384. /****************************************************************************
  385. return a base 36 character. v must be from 0 to 35.
  386. ****************************************************************************/
  387. static char base36(int v)
  388. {
  389.   v = v % 36;
  390.   if (v < 10)
  391.     return('0'+v);
  392.   else /* needed to work around a DEC C compiler bug */
  393.     return('A' + (v-10));
  394. }
  395.  
  396.  
  397. static void do_fwd_mangled_map(char *s, char *MangledMap)
  398. {
  399.   /* MangledMap is a series of name pairs in () separated by spaces.
  400.    * If s matches the first of the pair then the name given is the
  401.    * second of the pair.  A * means any number of any character and if
  402.    * present in the second of the pair as well as the first the
  403.    * matching part of the first string takes the place of the * in the
  404.    * second.
  405.    *
  406.    * I wanted this so that we could have RCS files which can be used
  407.    * by UNIX and DOS programs.  My mapping string is (RCS rcs) which
  408.    * converts the UNIX RCS file subdirectory to lowercase thus
  409.    * preventing mangling.
  410.    */
  411.   char *start=MangledMap;       /* Use this to search for mappings. */
  412.   char *end;                    /* Used to find the end of strings. */
  413.   char *match_string;
  414.   pstring new_string;           /* Make up the result here. */
  415.   char *np;                     /* Points into new_string. */
  416.  
  417.   DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap));
  418.   while (*start) {
  419.     while ((*start) && (*start != '('))
  420.       start++;
  421.     start++;                    /* Skip the ( */
  422.     if (!*start)
  423.       continue;                 /* Always check for the end. */
  424.     end = start;                /* Search for the ' ' or a ')' */
  425.     DEBUG(5,("Start of first in pair '%s'\n", start));
  426.     while ((*end) && !((*end == ' ') || (*end == ')')))
  427.       end++;
  428.     if (!*end) {
  429.       start = end;
  430.       continue;                 /* Always check for the end. */
  431.     }
  432.     DEBUG(5,("End of first in pair '%s'\n", end));
  433.     if ((match_string = map_filename(s, start, end-start))) {
  434.       DEBUG(5,("Found a match\n"));
  435.       /* Found a match. */
  436.       start = end+1;            /* Point to start of what it is to become. */
  437.       DEBUG(5,("Start of second in pair '%s'\n", start));
  438.       end = start;
  439.       np = new_string;
  440.       while ((*end)             /* Not the end of string. */
  441.              && (*end != ')')   /* Not the end of the pattern. */
  442.              && (*end != '*'))  /* Not a wildcard. */
  443.         *np++ = *end++;
  444.       if (!*end) {
  445.         start = end;
  446.         continue;               /* Always check for the end. */
  447.       }
  448.       if (*end == '*') {
  449.         strcpy(np, match_string);
  450.         np += strlen(match_string);
  451.         end++;                  /* Skip the '*' */
  452.         while ((*end)             /* Not the end of string. */
  453.                && (*end != ')')   /* Not the end of the pattern. */
  454.                && (*end != '*'))  /* Not a wildcard. */
  455.           *np++ = *end++;
  456.       }
  457.       if (!*end) {
  458.         start = end;
  459.         continue;               /* Always check for the end. */
  460.       }
  461.       *np++ = '\0';             /* NULL terminate it. */
  462.       DEBUG(5,("End of second in pair '%s'\n", end));
  463.       strcpy(s, new_string);    /* Substitute with the new name. */
  464.       DEBUG(5,("s is now '%s'\n", s));
  465.     }
  466.     start = end;              /* Skip a bit which cannot be wanted */
  467.     /* anymore. */
  468.     start++;
  469.   }
  470. }
  471.  
  472. /****************************************************************************
  473. do the actual mangling to 8.3 format
  474. ****************************************************************************/
  475. void mangle_name_83(char *s)
  476. {
  477.   int csum = str_checksum(s);
  478.   char *p;
  479.   char extension[4];
  480.   char base[9];
  481.   int baselen = 0;
  482.   int extlen = 0;
  483.  
  484.   extension[0]=0;
  485.   base[0]=0;
  486.  
  487.   p = strrchr(s,'.');  
  488.   if (p && (strlen(p+1)<4) )
  489.     {
  490.       BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
  491.       if (all_normal && p[1] != 0)
  492.     {
  493.       *p = 0;
  494.       csum = str_checksum(s);
  495.       *p = '.';
  496.     }
  497.     }
  498.       
  499.  
  500.   strupper(s);
  501.  
  502.   DEBUG(5,("Mangling name %s to ",s));
  503.  
  504.   if (p)
  505.     {
  506.       if (p == s)
  507.     strcpy(extension,"___");
  508.       else
  509.     {
  510.       *p++ = 0;
  511.       while (*p && extlen < 3)
  512.         {
  513.           if (isdoschar(*p) && *p != '.')
  514.         extension[extlen++] = *p;
  515.           p++;
  516.         }
  517.       extension[extlen] = 0;
  518.     }
  519.     }
  520.  
  521.   p = s;
  522.  
  523.   while (*p && baselen < 5)
  524.     {
  525.       if (isdoschar(*p) && *p != '.')
  526.     base[baselen++] = *p;
  527.       p++;
  528.     }
  529.   base[baselen] = 0;
  530.  
  531.   csum = csum % (36*36);
  532.  
  533.     sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36));
  534.  
  535.   if (*extension)
  536.     {
  537.       strcat(s,".");
  538.       strcat(s,extension);
  539.     }
  540.   DEBUG(5,("%s\n",s));
  541. }
  542.  
  543.  
  544.  
  545. /*******************************************************************
  546.   work out if a name is illegal, even for long names
  547.   ******************************************************************/
  548. static BOOL illegal_name(char *name)
  549. {
  550.   static unsigned char illegal[256];
  551.   static BOOL initialised=False;
  552.   unsigned char *s;
  553.  
  554.   if (!initialised) {
  555.     char *ill = "*\\/?<>|\":{}";
  556.     initialised = True;
  557.   
  558.     bzero((char *)illegal,256);
  559.     for (s = (unsigned char *)ill; *s; s++)
  560.       illegal[*s] = True;
  561.   }
  562.  
  563. #ifdef KANJI
  564.   for (s = (unsigned char *)name; *s;) {
  565.     if (is_shift_jis (*s)) {
  566.       s += 2;
  567.     } else if (illegal[*s]) {
  568.       return(True);
  569.     } else {
  570.       s++;
  571.     }
  572.   }
  573. #else
  574.   for (s = (unsigned char *)name;*s;s++)
  575.     if (illegal[*s]) return(True);
  576. #endif
  577.  
  578.  
  579.   return(False);
  580. }
  581.  
  582.  
  583. /****************************************************************************
  584. convert a filename to DOS format. return True if successful.
  585. ****************************************************************************/
  586. BOOL name_map_mangle(char *OutName,BOOL need83,int snum)
  587. {
  588. #ifdef MANGLE_LONG_FILENAMES
  589.   if (!need83 && illegal_name(OutName)) need83 = True;
  590. #endif  
  591.  
  592.   /* apply any name mappings */
  593.   {
  594.     char *map = lp_mangled_map(snum);
  595.     if (map && *map)
  596.       do_fwd_mangled_map(OutName,map);
  597.   }
  598.  
  599.   /* check if it's already in 8.3 format */
  600.   if (need83 && !is_8_3(OutName)) {
  601.     if (!lp_manglednames(snum)) return(False);
  602.  
  603.     /* mangle it into 8.3 */
  604.     push_mangled_name(OutName);  
  605.     mangle_name_83(OutName);
  606.   }
  607.   
  608.   return(True);
  609. }
  610.  
  611.